package com.deuwise.system.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.deuwise.common.base.BuildTree;
import com.deuwise.common.base.Tree;
import com.deuwise.common.exception.RException;
import com.deuwise.common.utils.*;
import com.deuwise.common.utils.poi.CreateFileUtil;
import com.deuwise.common.validator.ValidatorUtils;
import com.deuwise.common.validator.group.AddGroup;
import com.deuwise.common.validator.group.UpdateGroup;
import com.deuwise.system.entity.AppDo;
import com.deuwise.system.entity.MenuExport;
import com.deuwise.system.entity.SysMenu;
import com.deuwise.system.entity.from.SortModel;
import com.deuwise.system.service.AppDoService;
import com.deuwise.system.service.SysMenuService;

import com.deuwise.system.service.ShiroService;
import io.swagger.annotations.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 *@author deuwise
 *@date 2018-11-06 14:15:04
 */
@Api(tags = "菜单模块", description = "菜单模块")
@RequestMapping("api/SysMenu")
@RestController()
public class SysMenuController extends  AbstractController {
    @Autowired
    private SysMenuService sysMenuService;

    @Autowired
    private ShiroService shiroService;

    @Autowired
    private AppDoService appDoService;
    /**
     * 导航菜单
     */
    @ApiOperation("获取导航菜单")
    @GetMapping("/nav")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "code", value = "注册应用code", defaultValue = "dwAdmin", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "type", value = "是否展示菜单", defaultValue = "0", dataType = "Integer", paramType = "query")
    })
    @RequiresAuthentication
    public R nav(String code,Integer type){
        try {
            if (code == null || StringUtils.isBlank(code)) {
                code = DW_ADMIN;
            }
            Wrapper<AppDo> appDoWrapper = new EntityWrapper<>();
            appDoWrapper.eq("code", code);
            if (type == null || type == 1) {
                AppDo appDo = appDoService.selectOne(appDoWrapper);
                if (appDo.getStatus() == 0) {
                    return R.error(500, "系统已经被禁用");
                }
            }
            List<SysMenu> menuList = sysMenuService.getUserMenuList(getUserId(), code);
            Set<String> permissions = shiroService.getUserPermissions(getUserId());
            return R.ok().put("menuList", menuList).put("permissions", permissions);
        }catch (Exception ex){
            ex.printStackTrace();
        }
        return R.error();
    }

    /**
     * 导航菜单
     */
    @ApiOperation("导出菜单")
    @GetMapping("/exportMenu")
    @RequiresPermissions("sys:menu:export")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "code",required = true, value = "注册应用code", defaultValue = "dwAdmin", dataType = "String", paramType = "query")
    })
    public void exportMenu(String code, HttpServletResponse response){
        if(code==null||StringUtils.isBlank(code)){
            code=DW_ADMIN;
        }
        List<SysMenu> menuList = sysMenuService.getUserMenuList("1",code);
        List<MenuExport> exportList=new ArrayList<>();
        CreateFileUtil.createJsonFile(response,JSON.toJSONString(menuList),"menu-mock");

    }


    @ApiOperation(value = "批量导入菜单",notes = "模板下载地址=/menu-mock.json")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "code",required = true,value = "注册应用code", defaultValue = "dwAdmin", dataType = "String", paramType = "query")
    })
    @RequiresPermissions("sys:menu:import")
    @PostMapping(value = "/importMenu", consumes = "multipart/*", headers = "content-type=multipart/form-data")
    public R importMenu(@ApiParam(value = "上传文件", required = true) MultipartFile file,String code) {

        if(DW_ADMIN.equals(code)){
            return  R.error("后台管理系统不允许导入更新");
        }
        try {
            String fileName = file.getOriginalFilename();
            if (!fileName.contains(".json")) {
                return R.error("导入的文件格式不正确");
            }
        } catch (Exception e) {
            return R.error("导入的文件格式不正确");
        }
        try {
            String fileName = file.getOriginalFilename();
            if (!fileName.contains(".json")) {
                return R.error("导入的文件格式不正确");
            }
        } catch (Exception e) {
            return R.error("导入的文件格式不正确");
        }
        StringBuilder sb= FileUtil.getJsonStr(file);
        try {
            if (StringUtils.isNotBlank(sb.toString())) {
                Wrapper<SysMenu> wrapper = new EntityWrapper<>();
                wrapper.eq("app_id", code);
                List<SysMenu> allMenuList = sysMenuService.selectList(wrapper);
                List<SysMenu> menuList = JSONObject.parseArray(sb.toString(), SysMenu.class);

                Integer parentSort = menuList.size();
                for (SysMenu sysMenu : menuList) {
                    SysMenu addMenu = sysMenu;
                    if (StringUtils.isBlank(sysMenu.getId())) {
                        String name = sysMenu.getName();
                        Optional<SysMenu> menuOptional = allMenuList.stream().filter(f -> f.getName().equals(name.trim()) && f.getParentId().equals("0")).findFirst();
                        if (menuOptional.isPresent()) {
                            sysMenu = menuOptional.get();
                        } else {
                            sysMenu.setAppId(code);
                            sysMenu.setParentId("0");
                            sysMenu.setCreateTime(new Date());
                            sysMenu.setType(0);
                        }
                    }
                    if(sysMenu.getOrderNum()==null||sysMenu.getOrderNum()==0) {
                        sysMenu.setOrderNum(parentSort);
                    }
                    sysMenu.setList(addMenu.getList());
                    parentSort--;
                    sysMenu.setUpdateTime(new Date());

                    //重新设置APPId/id
                    sysMenu.setAppId(code);
                    sysMenu.setId(null);
                    sysMenuService.insertOrUpdate(sysMenu);
                    setChildUpdate(code, sysMenu, allMenuList);
                }
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }

        return  R.ok();

    }
    public static final String DW_ADMIN = "dwAdmin";

    @RequestMapping(value = "/clear", method = RequestMethod.POST)
    @ApiOperation("清空应用菜单")
    @RequiresPermissions("sys:menu:clear")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "code",required = true, value = "注册应用code", defaultValue = "dwAdmin", dataType = "String", paramType = "query")
    })
    public R clear(String code){

        if(DW_ADMIN.equals(code)){
            return  R.error("后台管理系统不允许清空");
        }
        Wrapper<SysMenu> wrapper = new EntityWrapper<>();
        wrapper.eq("app_id", code);
        sysMenuService.delete(wrapper);
        return R.ok();
    }


    void setChildUpdate(String code,SysMenu sysMenu,List<SysMenu>allMenuList){
        if(sysMenu.getList()!=null&&sysMenu.getList().size()>0){
            Integer childSort=sysMenu.getList().size();
            for(SysMenu subList:sysMenu.getList()){
                SysMenu addSubMenu=subList;
                subList.setParentId(sysMenu.getId());
                if(StringUtils.isBlank(subList.getId())) {
                    String name=subList.getName();
                    String parentId=sysMenu.getId();
                    Optional<SysMenu> menuOptional= allMenuList.stream().filter(f->f.getName().equals(name.trim())&&f.getParentId().equals(parentId)).findFirst();
                    if(menuOptional.isPresent()){
                        subList=menuOptional.get();
                    }else {
                        subList.setAppId(code);
                         if(addSubMenu.getList() != null && addSubMenu.getList().size() > 0){
                            subList.setType(0);
                         }else{
                            subList.setType(1);
                        }
                        subList.setCreateTime(new Date());
                    }

                }
                subList.setList(addSubMenu.getList());
                subList.setOrderNum(childSort);
                subList.setUpdateTime(new Date());
                // 重新设置id、parentId、appId
                subList.setId(null);
                subList.setAppId(code);
                subList.setParentId(sysMenu.getId());
                childSort--;
                sysMenuService.insertOrUpdate(subList);
                //添加子节点数据
                setChildUpdate(code,subList,allMenuList);
            }
        }
    }





    /**
     * 菜单信息
     */
    @GetMapping("/{menuId}")
    @ApiOperation("菜单信息")
    @RequiresPermissions("sys:menu:info")
    public R info(@PathVariable("menuId") String menuId){
        SysMenu menu = sysMenuService.selectById(menuId);
        return R.ok().put("menu", menu);
    }
    /**
     * 选择菜单(添加、修改菜单)
     */
    @ApiOperation("选择菜单(添加、修改菜单)")
    @GetMapping("/select")
    @RequiresPermissions("sys:menu:select")
    public R select(){
        //查询列表数据
        List<SysMenu> menuList = sysMenuService.queryNotButtonList();

        //添加顶级菜单
        SysMenu root = new SysMenu();
        root.setId("0");
        root.setName("一级菜单");
        root.setParentId("-1");
        root.setOpen(true);
        menuList.add(root);

        return R.ok().put("menuList", menuList);
    }

    /**
     * 所有菜单列表
     */
    @ApiOperation("菜单list")
    @GetMapping("/list")
    @ApiImplicitParam(name = "code", value = "注册应用code", defaultValue = "dwAdmin", dataType = "String", paramType = "query")
    @RequiresPermissions("sys:menu:list")
    public Result<List<Tree<SysMenu>>> list(String code){
        if(code==null||StringUtils.isBlank(code)){
            code=DW_ADMIN;
        }
        Wrapper<SysMenu> sysMenuWrapper=new EntityWrapper<>();
        sysMenuWrapper.eq("app_id",code);
        sysMenuWrapper.orderBy("order_num",true).orderBy("id",false);
        List<SysMenu> menuList = sysMenuService.selectList(sysMenuWrapper);
        List<Tree<SysMenu>> trees = new ArrayList<Tree<SysMenu>>();
        for(SysMenu sysMenuEntity : menuList){
            Tree<SysMenu> tree = new Tree<SysMenu>();
            SysMenu parentMenuEntity = sysMenuService.selectById(sysMenuEntity.getParentId());
            if(parentMenuEntity != null){
                sysMenuEntity.setParentName(parentMenuEntity.getName());
            }
            tree.setId(sysMenuEntity.getId());
            tree.setParentId(sysMenuEntity.getParentId());
            tree.setText(sysMenuEntity.getName());
            Map<String, Object> map=new HashMap<>(16);
            map.put("icon",sysMenuEntity.getIcon());
            map.put("perms",sysMenuEntity.getPerms());
            map.put("appId",sysMenuEntity.getAppId());
            map.put("url",sysMenuEntity.getUrl());
            map.put("orderNum",sysMenuEntity.getOrderNum());
            map.put("parentName",sysMenuEntity.getParentName());
            map.put("type",sysMenuEntity.getType());
            tree.setAttributes(map);
            trees.add(tree);
        }

        Tree<SysMenu> sysMenuTree= BuildTree.build(trees);
        List<Tree<SysMenu>> treeList=new ArrayList<>();
        if(sysMenuTree.getChildren()!=null){
            treeList=sysMenuTree.getChildren();
        }else{
            treeList.add(sysMenuTree);
        }
        return Result.ok(treeList);
    }

    @ApiOperation(value = "新增数据")
    @PostMapping()
    @RequiresPermissions("sys:menu:save")
    public R insertSysMenu(@RequestBody SysMenu sysMenu){
        boolean isSuccess = false;
        if(null == sysMenu){
            return R.error(200,"新增数据失败，请稍后再试!");
        }
        //数据校验
        verifyForm(sysMenu);
        int count = sysMenuService.queryByName(sysMenu.getName(),sysMenu);
        if (count > 0) {
            return R.error(200, "菜单名称不能重复");
        }
        isSuccess = sysMenuService.insert(sysMenu);
        if (isSuccess) {
            return R.ok(sysMenu);
        } else {
            return R.error(200,"新增数据失败，请稍后再试!");
        }
    }
    @ApiOperation("修改菜单")
    @PutMapping("")
    @RequiresPermissions("sys:menu:update")
    public R update(@RequestBody SysMenu menu){
        //数据校验
        verifyForm(menu);
        int count = sysMenuService.queryByName(menu.getName(),menu);
        if (count > 0) {
            return R.error(200, "菜单名称不能重复");
        }
        sysMenuService.updateById(menu);

        return R.ok();
    }

    @ApiOperation("排序菜单")
    @PostMapping("/sortMenu")
    public R sortMenu(@RequestBody List<SortModel> list){
        //数据校验
        //ValidatorUtils.validateEntity(sortModel, UpdateGroup.class);
        List<SysMenu> sysMenuList=new ArrayList<>();
        for(SortModel sortModel:list){
            SysMenu menu=new SysMenu();
            menu.setId(sortModel.getId());
            menu.setOrderNum(sortModel.getOrderNum());
            sysMenuList.add(menu);
        }
        sysMenuService.updateBatchById(sysMenuList);

        return R.ok();
    }



    @ApiOperation(value = "批量删除记录")
    @RequiresPermissions("sys:menu:delete")
    @RequestMapping(value = "/deleteSelect", method = RequestMethod.POST)
    public  R deleteSelect(@ApiParam(value = "ids集合",name = "ids",required = true) @RequestParam String[] ids){
        try {
            if (ids != null && ids.length > 0) {
                    sysMenuService.deleteBatchIds(Arrays.asList(ids));
            }
        }catch (Exception ex){
            return  R.error("删除失败");
        }
        return  R.ok();
    }
    @ApiOperation("删除菜单")
    @DeleteMapping("/{menuId}")
    @RequiresPermissions("sys:menu:delete")
    public R delete(@PathVariable("menuId") String menuId){

        //判断是否有子菜单或按钮
        List<SysMenu> menuList = sysMenuService.queryListParentId(menuId,"");
        if(menuList.size() > 0){
            List<String> menuIds = menuList.stream().map(SysMenu::getId).collect(Collectors.toList());
            //删除子菜单
            sysMenuService.deleteBatchIds(menuIds);
        }
        sysMenuService.deleteById(menuId);
        return R.ok();
    }

    /**
     * 验证参数是否正确
     */
    private void verifyForm(SysMenu menu){
        if(StringUtils.isBlank(menu.getName())){
            throw new RException("菜单名称不能为空");
        }

        if(menu.getParentId() == null){
            throw new RException("父级菜单不能为空");
        }

        //菜单
        if(menu.getType() == Constant.MenuType.MENU.getValue()){
            if(StringUtils.isBlank(menu.getUrl())){
                throw new RException("菜单URL不能为空");
            }
        }

        //上级菜单类型
        int parentType = Constant.MenuType.CATALOG.getValue();
        if(!"0".equals(menu.getParentId())){
            SysMenu parentMenu = sysMenuService.selectById(menu.getParentId());
            parentType = parentMenu.getType();
        }

        //目录、菜单
        if(menu.getType() == Constant.MenuType.CATALOG.getValue() ||
                menu.getType() == Constant.MenuType.MENU.getValue()){
            if(parentType != Constant.MenuType.CATALOG.getValue()){
                throw new RException("父级菜单只能为目录类型");
            }
            return ;
        }

        //按钮
        if(menu.getType() == Constant.MenuType.BUTTON.getValue()){
            if(parentType != Constant.MenuType.MENU.getValue()){
                throw new RException("父级菜单只能为菜单类型");
            }
        }
    }

}